/**
 * @copyright (c) 2024, MacRsh
 *
 * @license SPDX-License-Identifier: Apache-2.0
 *
 * @date 2024-08-05    MacRsh       First version
 */

#ifndef __LIST_H__
#define __LIST_H__

#include <errno.h>
#include <malloc.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/**
 * @addtogroup List
 * @{
 */

/**
 * @struct ListHead
 * @brief Represents a doubly list head.
 */
typedef struct ListHead {
    struct ListHead *prev;
    struct ListHead *next;
} ListHead_t;

/**
 * @struct ListNode
 * @brief Represents a double list node.
 */
typedef struct ListNode {
    ListHead_t head;
    void *data;
} ListNode_t;

/**
 * @struct List
 * @brief Represents a double list.
 */
typedef struct List {
    ListHead_t head;
} List_t;

/**
 * @brief This macro iterates over the list head.
 *
 * @param _pos The iterator variable.
 * @param _list The list head.
 */
#define LIST_HEAD_FOR_EACH(_pos, _list)                                        \
    for ((_pos) = (_list)->next; (_pos) != (_list); (_pos) = (_pos)->next)

/**
 * @brief This macro iterates over the list head with safe.
 *
 * @param _pos The iterator variable.
 * @param _tmp The temporary variable.
 * @param _list The list head.
 */
#define LIST_HEAD_FOR_EACH_SAFE(_pos, _tmp, _list)                             \
    for ((_pos) = (_list)->next, (_tmp) = (_pos)->next; (_pos) != (_list);     \
         (_pos) = (_tmp), (_tmp) = (_pos)->next)

/**
 * @brief This macro returns the entry of the list head.
 *
 * @param _pos The iterator variable.
 * @param _type The type of the entry.
 * @param _member The member of the entry.
 */
#define LIST_HEAD_ENTRY(_pos, _type, _member)                                  \
    ((_type *)((char *)(_pos) - (uintptr_t)(&((_type *)0)->_member)))

void list_head_init(ListHead_t *list);
void list_head_deinit(ListHead_t *list);
ListHead_t *list_head_new(void);
void list_head_del(ListHead_t *node);
void list_head_push_back(ListHead_t *list, ListHead_t *node);
void list_head_push_front(ListHead_t *list, ListHead_t *node);
void list_head_push(ListHead_t *list, ListHead_t *node);
ListHead_t *list_head_pop_back(ListHead_t *list);
ListHead_t *list_head_pop_front(ListHead_t *list);
ListHead_t *list_head_pop(ListHead_t *list);
void list_head_insert(ListHead_t *list, ListHead_t *node);
void list_head_remove(ListHead_t *list);
void list_head_concat(ListHead_t *list, ListHead_t *head);
void list_head_clear(ListHead_t *list);
ListHead_t *list_head_first(ListHead_t *list);
ListHead_t *list_head_last(ListHead_t *list);
size_t list_head_len(ListHead_t *list);
bool list_head_is_empty(ListHead_t *list);

/**
 * @brief This macro iterates over the list.
 *
 * @param _pos The iterator variable(ListNode).
 * @param _list The list to iterate over.
 */
#define LIST_FOR_EACH(_pos, _list)                                             \
    for ((_pos) = (ListNode_t *)(_list)->head.next;                            \
         (ListHead_t *)(_pos) != &(_list)->head;                               \
         (_pos) = (ListNode_t *)(_pos)->head.next)

/**
 * @brief This macro iterates over the list with safe.
 *
 * @param _pos The iterator variable(ListNode).
 * @param _tmp The temporary variable(ListNode).
 * @param _list The list to iterate over.
 */
#define LIST_FOR_EACH_SAFE(_pos, _tmp, _list)                                  \
    for ((_pos) = (ListNode_t *)(_list)->head.next,                            \
        (_tmp) = (ListNode_t *)(_pos)->head.next;                              \
         (ListHead_t *)(_pos) != &(_list)->head;                               \
         (_pos) = (_tmp), (_tmp) = (ListNode_t *)(_pos)->head.next)

void list_init(List_t *list);
void list_deinit(List_t *list);
List_t *list_new(void);
void list_del(List_t *list);
int list_push_back(List_t *list, void *data);
int list_push_front(List_t *list, void *data);
int list_push(List_t *list, void *data);
void *list_pop_back(List_t *list);
void *list_pop_front(List_t *list);
void *list_pop(List_t *list);
int list_insert(List_t *list, void *data);
void list_clear(List_t *list);
void list_append(List_t *list, List_t *other);
void *list_first(List_t *list);
void *list_last(List_t *list);
size_t list_len(List_t *list);
bool list_is_empty(List_t *list);

/** @} */

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* __LIST_H__ */
